
#include "member_BTerrain.h"
#include "member_BShape.h"
#include "member_BScene.h"

using namespace BWE;

member_BTerrain::member_BTerrain(BTerrain* terrain)
{
	boss = terrain;
	align = Align_LeftBottom;
	width = 1;
	height = 1;
	skirtHeight = 0;
	elevation.setColumn(3);
	elevation.setRow(3);
	dirtyArea = true;
	dirtyZone = true;
	dirtySkirt = true;
}
member_BTerrain::~member_BTerrain()
{

}

bool member_BTerrain::rebuild()
{
	const BVector& min = localSpace.min();
	int count = elevation.size();
	if (count == 0)
	{
		boss->clear();
		return true;
	}

	if (!vertices)
	{
		vertices = new BVectorArray();
		normals = new BVectorArray();
		coords = new BCoordArray();
	}

	BReal* zs = elevation.data();
	int column = elevation.column();
	int row = elevation.row();

	if (vertices->size() != count)
	{
		dirtyArea = false;
		vertices->resize(count);
		normals->resize(count);
		coords->resize(count);

		BVector normal(0, 0, 1);
		BReal xunit = width / (column - 1);
		BReal yunit = height / (row - 1);
		float tdx = 1.0f / (column - 1);
		float tdy = 1.0f / (row - 1);
		BReal w = xunit * (column - 1);
		for (int r = 0; r < row; r++)
		{
			int head = r * column;
			BReal y = yunit * r;
			float ty = 1.0f - tdy * r;
			for (int c = 0; c < column; c++)
			{
				int index = head + c;
				BReal x = xunit * c;
				BReal z = zs[index];
				(*vertices)[index] = min + BVector(x, y, z);
				(*normals)[index] = normal;
				(*coords)[index].set(tdx * c, ty);
			}
		}
	}

	int widthSegment = column - 1;
	int heightSegment = row - 1;
	int indexSize = widthSegment * heightSegment * 4;
	if (indices.empty() || indices->size() != indexSize)
	{
		indices = new BIndexArray(indexSize);
	}
	for (int r = 0; r < heightSegment; r++)
	{
		int head = r * (widthSegment + 1);
		int pos = r * widthSegment * 4;
		for (int c = 0; c < widthSegment; c++)
		{
			int i0 = head + c;
			int i1 = i0 + 1;
			int i2 = i1 + (widthSegment + 1);
			int i3 = i0 + (widthSegment + 1);
			(*indices)[pos + c * 4] = i0;
			(*indices)[pos + c * 4 + 1] = i1;
			(*indices)[pos + c * 4 + 2] = i2;
			(*indices)[pos + c * 4 + 3] = i3;
		}
	}

	if (dirtyArea)
	{
		BReal xunit = width / (column - 1);
		BReal yunit = height / (row - 1);
		for (int r = 0; r < row; r++)
		{
			int head = r * column;
			BReal y = yunit * r;
			for (int c = 0; c < column; c++)
			{
				int index = head + c;
				BReal x = xunit * c;
				(*vertices)[index].x() = x + min.x();
				(*vertices)[index].y() = y + min.y();
			}
		}
		boss->smooth();
		dirtyArea = false;
	}

	return true;
}

void member_BTerrain::slotFreshQuadTree()
{
	BSpace treeSpace = quadTree->space();
	if (quadTree->empty() || !treeSpace.contain(localSpace))
	{
		quadTree->reset(localSpace);
		for (int i = 0; i < indices->size(); i += 4)
		{
			int ia = indices->at(i);
			int ib = indices->at(i + 1);
			int ic = indices->at(i + 2);
			int id = indices->at(i + 3);
			const BVector& va = vertices->at(ia);
			const BVector& vb = vertices->at(ib);
			const BVector& vc = vertices->at(ic);
			const BVector& vd = vertices->at(id);
			BSpace space(va);
			space.expand(vb);
			space.expand(vc);
			space.expand(vd);

			QuadTreeItem item = quadTree->create(space);
			item->append(ia);
			item->append(ib);
			item->append(ic);
			item->append(id);
		}
	}
}
